package com.magic.service.recharge;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import com.magic.auth.TokenUtil;
import com.magic.consts.PayEnum;
import com.magic.consts.TradeEnum;
import com.magic.entity.pay.TradeForm;
import com.magic.entity.user.Flower;
import com.magic.entity.user.User;
import com.magic.repository.IFlowerRepository;
import com.magic.repository.ITradeFormRepository;
import com.magic.repository.IUserRepository;
import com.magic.result.Result;
import com.magic.util.DateUtil;
import com.magic.util.RandomCode;
import com.magic.util.pay.PayUtil;
import com.magic.util.pay.XMLUtil;
import com.magic.vo.pay.RechargeVo;

/**
 * ClassName: PayService <br/>
 * Function: pay service. <br/>
 * date: 2018年10月16日 下午5:26:18 <br/>
 * 
 * @author lishuai11
 * @version
 * @since JDK 1.8
 */
@Service("payService")
public class PayService {

	private static final String ORDER_DETAIL = "神奇种子：充值花种";

	private static final Logger logger = LoggerFactory.getLogger(PayService.class);

	@Autowired
	RestTemplate restTemplate;

	@Autowired
	IUserRepository userRepository;

	@Autowired
	ITradeFormRepository tradeFormRepository;

	@Autowired
	IFlowerRepository flowerRepository;

	@Value("${wechat.appid}")
	private String appId;

	@Value("${wechat.mchid}")
	private String mchId;

	@Value("${wechat.mchpass}")
	private String mchPass;

	@Value("${wechat.pay.unifiedorder}")
	private String unifiedorder;

	@Value("${pay.callback-url}")
	private String callbackUrl;

	/**
	 * 
	 * recharge:(充值). <br/>
	 * 
	 * @author lishuai11
	 * @param rechargeVo
	 * @return
	 * @since JDK 1.8
	 */
	public synchronized Result recharge(RechargeVo rechargeVo, String token) {
		try {
			String payType = rechargeVo.getPayType();
			User user = userRepository.findOne(rechargeVo.getUserId());
			if (user == null) {
				return Result.fail(Result.CLIENT_ERROR, "用户不存在");
			}
			if (!TokenUtil.resourceAudit(token, user.getUserId())) {
				return Result.fail(Result.CLIENT_ERROR, "Authorization is not valid  | userId is not valid");
			}
			String orderDetail = ORDER_DETAIL;
			int price = rechargeVo.getPrice();
			String openId = user.getOpenId();
			// 暂时处理：微信小程序待更新
			if (openId == null || openId.equals("")) {
				openId = "1234";
			}
			TradeForm tradeForm = new TradeForm(user.getUserId(), orderDetail, price);
			while (true) {
				String tradeCode = RandomCode.generateShortUuid();
				if (tradeFormisNotExist(tradeCode)) {
					tradeForm.setTradeCode(tradeCode);
					tradeForm = tradeFormRepository.save(tradeForm);
					break;
				}
			}
			return payType.equals(PayEnum.WESM.getValue()) ? wesmPay(tradeForm, openId)
					: (payType.equals(PayEnum.WECHAT.getValue()) ? wechatPay(tradeForm)
							: Result.fail(Result.CLIENT_ERROR, "只支持微信支付"));
		} catch (Exception e) {
			logger.error("recharge()方法异常：{},{}", e.getMessage(), e);
			return Result.fail(Result.SERVER_ERROR, "服务器异常");
		}
	}

	public Result stopTrade(String tradeCode, String token) {
		try {
			List<TradeForm> list = tradeFormRepository.findByTradeCode(tradeCode);
			if (list != null && !list.isEmpty()) {
				TradeForm tradeForm = list.get(0);
				if (!TokenUtil.resourceAudit(token, tradeForm.getUserId())) {
					return Result.fail(Result.CLIENT_ERROR, "Authorization is not valid  | userId is not valid");
				}
				tradeFormRepository.deleteByTradeCode(tradeCode);
				return Result.success("取消成功");
			} else {
				return Result.fail(Result.CLIENT_ERROR, "编码不存在");
			}
		} catch (Exception e) {
			logger.error("stopTrade异常：{}", e.getMessage(), e);
			return Result.fail(Result.SERVER_ERROR, "服务器异常");
		}

	}

	public Result rechargeResult(int userId, String tradeCode, String token) {
		try {
			if (!TokenUtil.resourceAudit(token, userId)) {
				return Result.fail(Result.CLIENT_ERROR, "Authorization is not valid  | userId is not valid");
			}
			List<TradeForm> list = tradeFormRepository.findByUserIdAndTradeCode(userId, tradeCode);
			if (list != null && !list.isEmpty()) {
				TradeForm tradeForm = list.get(0);
				return Result.success("success", tradeForm);
			} else {
				return Result.fail(404, "没有交易记录");
			}
		} catch (Exception e) {
			logger.error("rechargeResult异常：{}", e.getMessage(), e);
			return Result.fail(Result.SERVER_ERROR, "服务器异常");
		}
	}

	public Result rechargeForm(int userId, String token) {
		List<TradeForm> list = tradeFormRepository.findByUserId(userId);
		return Result.success("成功", list);
	}

	private Result wesmPay(TradeForm tradeForm, String openId) throws Exception {
		// 随机码
		String nonce_str = String.valueOf(System.currentTimeMillis());
		SortedMap<String, Object> params = new TreeMap<String, Object>();
		params.put("appid", appId);
		params.put("mch_id", mchId);
		params.put("nonce_str", nonce_str);
		params.put("body", tradeForm.getTradeDetail());
		params.put("out_trade_no", tradeForm.getTradeCode());
		params.put("fee_type", "CNY");
		params.put("total_fee", tradeForm.getMoney());
		params.put("notify_url", callbackUrl);
		params.put("trade_type", "JSAPI");
		params.put("openid", openId);
		String sign = PayUtil.createSign("UTF-8", params, mchPass);
		params.put("sign", sign);
		String requestXML = PayUtil.getRequestXml(params);
		String response = restTemplate.postForObject(unifiedorder, requestXML, String.class);
		Map<String, String> map = XMLUtil.doXMLParse(response);
		if (map != null) {
			if (map.get("return_code").equals("SUCCESS")) {
				if (map.get("result_code").equals("SUCCESS")) {
					String prepay_id = (String) map.get("prepay_id");
					SortedMap<String, Object> smap = new TreeMap<String, Object>();
					smap.put("appId", appId);
					smap.put("nonceStr", map.get("nonce_str"));
					smap.put("package", "prepay_id=" + prepay_id);
					smap.put("signType", "MD5");
					smap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
					String paySign = PayUtil.createSign("UTF-8", smap, mchPass);
					smap.put("paySign", paySign);
					smap.put("tradeCode", tradeForm.getTradeCode());
					return Result.success("success", map);
				} else {
					JSONObject jsonObject = new JSONObject();
					jsonObject.put(map.get("err_code"), map.get("err_code_des"));
					tradeForm.setTradeTime(DateUtil.localTimeBySms());
					tradeForm.setTradeStatus(TradeEnum.STATUS_FAIL.getValue());
					tradeForm.setFailReason(map.get("err_code_des"));
					tradeFormRepository.save(tradeForm);
					return Result.fail(4002, jsonObject.toJSONString());
				}
			} else {
				return Result.fail(4001, "签名失败:" + map.get("return_msg"));
			}
		} else {
			return Result.fail(4001, "支付失败");
		}
	}

	public Result wechatPay(TradeForm tradeForm) {
		return Result.fail(Result.SERVER_ERROR, "待开发");
	}

	@Transactional
	public synchronized void callback(HttpServletRequest request, HttpServletResponse response) {
		try {
			BufferedReader br = new BufferedReader(
					new InputStreamReader((ServletInputStream) request.getInputStream()));
			String line = null;
			StringBuilder result = new StringBuilder();
			while ((line = br.readLine()) != null) {
				result.append(line);
			}
			br.close();
			String notityXml = result.toString();
			String resXml = "";
			Map<String, String> map = XMLUtil.doXMLParse(notityXml);
			String returnCode = (String) map.get("return_code");
			if ("SUCCESS".equals(returnCode)) {
				@SuppressWarnings("unused")
				String timestamp = map.get("nonce_str");// 随机字符串，可用做处理相关认证
				// 做金额对比验证，字段顺序验证========暂时放弃
				String tradeCode = map.get("out_trade_no");
				String openid = map.get("openid");
				User user = userRepository.findByOpenId(openid).get(0);
				List<TradeForm> list = tradeFormRepository.findByUserIdAndTradeCode(user.getUserId(), tradeCode);
				if (list != null && !list.isEmpty()) {
					TradeForm tradeForm = list.get(0);
					tradeForm.setTradeStatus(TradeEnum.STATUS_SUCCESS.getValue());
					tradeForm.setTradeTime(DateUtil.localTimeBySms());
					tradeForm = tradeFormRepository.save(tradeForm);
					List<Flower> flowers = flowerRepository.findByUserId(user.getUserId());
					if (flowers != null && !flowers.isEmpty()) {
						Flower flower = flowers.get(0);
						BigDecimal seed = flower.getRechargeSeed();
						BigDecimal recharge = new BigDecimal(tradeForm.getMoney());
						recharge = recharge.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
						flower.setRechargeSeed(seed.add(recharge));
						flower.setAllSeed(flower.getRechargeSeed().add(flower.getEarnSeed()));
						flower = flowerRepository.save(flower);
					}
					resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
							+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
				}
			} else {
				logger.error("wechat callback签名失败：{}", map.get("return_msg"));
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
						+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
			}
			BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
			out.write(resXml.getBytes());
			out.flush();
			out.close();
		} catch (Exception e) {
			logger.error("异常：{}", e);
		}
	}

	private boolean tradeFormisNotExist(String tradeCode) {
		List<TradeForm> tradeForms = tradeFormRepository.findByTradeCode(tradeCode);
		if (tradeForms == null || tradeForms.isEmpty()) {
			return true;
		} else {
			return false;
		}
	}

}
